package server.net.handler;

import game.GameInstance;
import game.GameState;
import game.Player;
import java.nio.ByteBuffer;
import server.net.Client;
import shared.net.protocol.PacketCreator;

/**
 * Handles a client's player move request
 *
 * @author Andrew Gratta <andrew.gratta@stonybrook.edu>
 * @author Vincent Tsuei
 * @version 2012-11-29
 */
public class PlayerMoveHandler implements ServerPacketHandler {

    private final String NOT_LOGGED_IN_ERROR = "Error: You are not logged in";
    private final String NOT_IN_GAME_ERROR = "Error: You are not playing a game";
    private final String NOT_YOUR_TURN_ERROR = "Error: It is not your turn";
    private final String INVALID_MOVE_ERROR = "Error: The move is invalid";
    private final String GAME_OVER_ERROR = "Error: The game is over. No more moves can be made.";
    private final String GAME_OVER_MESSAGE = " has won the game!\nReturning to lobby...";

    @Override
    public int processPacket(Client client, ByteBuffer packet) {
        if (client == null || packet == null) {
            return -1;
        }


        //Check that the client is logged in
        if (!client.isLoggedIn()) {
            client.getConnection().queuePacketSend(PacketCreator.IN_GAME
                    .getPlayerMoveFailureResponse(NOT_LOGGED_IN_ERROR));
            return -1;
        }
        Player player = client.getPlayer();

        //If the player is NOT playing a game
        if (!player.isPlaying()) {
            client.getConnection().queuePacketSend(PacketCreator.IN_GAME
                    .getPlayerMoveFailureResponse(NOT_IN_GAME_ERROR));
            return -1;
        }
        GameInstance game = player.getGame();
        String P1Name = game.getFirstPlayer().getName();
        String P2Name = game.getSecondPlayer().getName();

        //Check that the game hasn't already ended.
        if (game.isOver()) {
            client.getConnection().queuePacketSend(PacketCreator.IN_GAME
                    .getPlayerMoveFailureResponse(GAME_OVER_ERROR));
            return -1;
        }

        //If it is the player's turn
        if (!player.canMakeMove()) {
            client.getConnection().queuePacketSend(PacketCreator.IN_GAME
                    .getPlayerMoveFailureResponse(NOT_YOUR_TURN_ERROR));
            return -1;
        }
        int n = packet.getInt();
        int s = packet.getInt();

        //Attempt to make the move. If the move is invalid, return a failure response.
        if (!player.makeMove(n, s)) {
            client.getConnection().queuePacketSend(PacketCreator.IN_GAME
                    .getPlayerMoveFailureResponse(INVALID_MOVE_ERROR));
            return -1;
        }


        //The move was valid, update players and observers
        GameState gameState = game.getGameState();
        Player opposingPlayer = game.getFirstPlayer();
        if (opposingPlayer == player) {
            opposingPlayer = game.getSecondPlayer();
        }
        String updateMessage = game.getBoardString();
//        //Player opposingPlayer = game.getWaitingPlayer();  //#BUGG
//        Player opposingPlayer = game.getActivePlayer(); //BUGGGGGGG

        //Check if the game is over
        if (gameState == GameState.GAME_OVER) {
            updateMessage = player.getName() + GAME_OVER_MESSAGE + "\n" + updateMessage;
        }

        //Update the player
        client.getConnection().queuePacketSend(PacketCreator.IN_GAME.getGameUpdate(updateMessage,
                game.getGameID(), false,
                game.getNumPiles(), game.getPiles()));

        //Update the opposing player
        Client opposingClient = opposingPlayer.getClient();
        opposingClient.getConnection().queuePacketSend(
                PacketCreator.IN_GAME.getGameUpdate(updateMessage,
                game.getGameID(), true,
                game.getNumPiles(), game.getPiles()));

        //Update the observers
        Player[] observers = game.getObservers();
        for (Player o : observers) {
            o.getClient().getConnection().queuePacketSend(PacketCreator.LOBBY.OBSERVE
                    .getObserveUpdateNotify(game.getGameID(),
                    P1Name, P2Name, opposingPlayer.getName(), game.getNumPiles(), game.getPiles(), gameState == GameState.GAME_OVER ? player.getName() : null));
        }

        //End of game cleanups.
        //Send the game over notifies
        if (gameState == GameState.GAME_OVER) {
            game.EndGame();
            client.getGameServer().getServerRegistry().deregisterGame(game);
        }
        return 0;
    }
}
